﻿using ATM.Components;
using ATM.Model;
using ATM.Utilities;
using System;

namespace ATM
{
    class Program
    {

        private static AtmEngine atmEngine = new AtmEngine();

        static void Main(string[] args)
        {

            // ATM is idling - it never shuts down and it can handle as many customers as needed
            while (true)
            {
                System.Console.WriteLine(">> UI: ATM is idle.");
                // By pressing a key on keyboard we simulate that customer puts a card into the reader...
                System.Console.WriteLine(">> UI: Press any key to insert credit card...");
                System.Console.ReadKey(true);

                // ... and this is a sign that ATM should start transaction.
                bool transactionStarted = atmEngine.StartTransacation();

                if (transactionStarted)
                {
                    // Let's read the credit card now
                    bool cardReadSuccessfully = atmEngine.ReadCreditCard();

                    // If credit card was read successfully within 3 times, transaction continues
                    if (cardReadSuccessfully)
                    {

                        // Let's check printer status. If it is not operable, we need to ask user if he can live with that
                        bool printerOk = atmEngine.CheckPrinter();
                        bool userWantsToContinueWithoutPrinter = true;
                        if (!printerOk)
                        {
                            System.Console.WriteLine(">> UI: Printer is not operating. If you want to continue without confirmations press 'y'. ");
                            ConsoleKeyInfo keyPressed = System.Console.ReadKey(true);
                            if (keyPressed.KeyChar != 'y')
                            {
                                userWantsToContinueWithoutPrinter = true;
                            }
                        }

                        // If printer is operating or user agreed that he will not get confirmations we continue
                        if (printerOk || (!printerOk && userWantsToContinueWithoutPrinter))
                        {
                            // Credit card will now be validated with bank
                            CreditCardVerificationStatus creditCardVerificationStatus = atmEngine.VerifyCreditCard();

                            // If verification was successful then user can continue with transaction
                            if (creditCardVerificationStatus == CreditCardVerificationStatus.OK)
                            {
                                // Let's read the pinCode
                                PinCodeVerificationStatus pinCodeVerificationStatus = ReadPinCode();

                                if (pinCodeVerificationStatus == PinCodeVerificationStatus.OK)
                                {
                                    // If the pincode is correct customer can withdraw money
                                    WithDrawAmount();

                                    //It does not really matter what the outcome of the operation is. Lets thank this guy for using our ATM ( ＾◡＾)
                                    System.Console.WriteLine(">> UI: Thank you for using this ATM. You are welcomed to take more cash again!");
                                }
                                else if (pinCodeVerificationStatus == PinCodeVerificationStatus.FAILED_CARD_LOCKED)
                                {
                                    // Or else if user locked his card by entering PIN too many times we end the transaction
                                    System.Console.WriteLine(">> UI: You failed to enter PIN code too many times. Your card will be withheld. Please contact your bank.");
                                }

                            }
                            else if (creditCardVerificationStatus == CreditCardVerificationStatus.INVALID)
                            {
                                // Credit card is invalid user cannot continue with transaction and he will get his card back
                                System.Console.WriteLine(">> UI: Your card is invalid. Your card will be ejected now. Please contact your bank.");
                            }
                            else if (creditCardVerificationStatus == CreditCardVerificationStatus.BLOCKED)
                            {
                                // Credit card is blocked and user will not get his card back, he will get a confirmation instead
                                System.Console.WriteLine(">> UI: Your card is invalid. Your card will be withheld. Please contact your bank.");
                            }
                        }
                        else
                        {
                            // If ATM will fail to read a card it will notify user about this fact and will abort transaction
                            System.Console.WriteLine(">> UI: Failed to read credit card number. Your card will be ejected. Please contact your bank or try again later.");
                        }
                    }
                    else
                    {
                        // If user does not want to continue without printer we finish the transaction
                        System.Console.WriteLine(">> UI: You chose to abort operation. Your card will be ejected now.");
                    }
                }
                else
                {
                    // If user does not want to continue without printer we finish the transaction
                    System.Console.WriteLine(">> UI: This ATM does not have connection to bank. Please try again later.");
                }

                System.Console.WriteLine("");
                System.Console.WriteLine("");

                // End transaction to put ATM in idle mode
                atmEngine.EndTransaction();
            }
        }

        private static PinCodeVerificationStatus ReadPinCode()
        {
            PinCodeVerificationStatus status;
            do
            {
                System.Console.Write(">> UI: Please enter your PIN code: ");
                string input = null;
                do
                {
                    input = System.Console.ReadLine();
                } while (!ValidationUtilities.IsPinCode(input));
                status = atmEngine.VerifyPinCode(input);
            } while (status != PinCodeVerificationStatus.OK && status != PinCodeVerificationStatus.FAILED_CARD_LOCKED);

            return status;
        }

        private static WithdrawStatus WithDrawAmount()
        {
            System.Console.WriteLine(">> UI: Choose amount to withdraw:");
            System.Console.WriteLine("1) DKK 100");
            System.Console.WriteLine("2) DKK 200");
            System.Console.WriteLine("3) DKK 500");
            System.Console.WriteLine("4) DKK 1000");
            System.Console.WriteLine("5) DKK 2000");
            System.Console.WriteLine("Press 'a' to abort transaction.");

            WithdrawStatus status;
            bool finishWithdraw = false;
            int amount = 0;
            int attempts = 0;

            //We will try maximum 3 times to select appropriate amount
            do
            {
                ConsoleKeyInfo input = System.Console.ReadKey();

                // Operation will abort if user presses 'a' or tries more than 3 times
                if (input.KeyChar == 'a' || attempts > 2)
                {
                    status = WithdrawStatus.ABORTED;
                    finishWithdraw = true;
                }
                else
                {
                    switch (input.KeyChar)
                    {
                        case '1':
                            amount = 100;
                            break;
                        case '2':
                            amount = 200;
                            break;
                        case '3':
                            amount = 500;
                            break;
                        case '4':
                            amount = 1000;
                            break;
                        case '5':
                            amount = 2000;
                            break;
                    }
                    status = atmEngine.Withdraw(amount);

                    // If withdraw was successful then cool ( ͡° ͜ʖ ͡°)
                    if (status == WithdrawStatus.OK)
                    {
                        finishWithdraw = true;
                    }
                    else if (status == WithdrawStatus.FAILED_NOT_ENOUGH_FUNDS)
                    {
                        // If clients has not enough fundds lets ask him to pick another amount
                        System.Console.WriteLine(">> UI: You do not have enough funds on your account. Please try again with smaller amount.");
                    }
                    else if (status == WithdrawStatus.FAILED_NOT_ENOUGH_CASH_IN_ATM)
                    {
                        // If there is not enough cash in ATM we should also notify customer
                        System.Console.WriteLine(">> UI: This ATM has not enough funds. Please try again with smaller amount.");
                    }
                }
                ++attempts;
            } while (!finishWithdraw);

            return status;
        }

    }
}
